Skip to main content

DeadmanSwitch Technical Documentation

Overview

DeadmanSwitch is a Solidity smart contract module designed for account recovery in cases of user inactivity. It implements a safety mechanism allowing a designated nominee to recover access to an account after a specified period of inactivity.

License

AGPL-3.0-only

Solidity Version

^0.8.25

Dependencies

  • modulekit/Modules.sol: ERC7579ValidatorBase, ERC7579HookBase
  • modulekit/ModuleKit.sol: PackedUserOperation
  • solady/utils/SignatureCheckerLib.sol
  • solady/utils/ECDSA.sol

Key Components

Constants & Storage

DeadmanSwitchStorage Struct

struct DeadmanSwitchStorage {
uint48 lastAccess; // Timestamp of the last account activity
uint48 timeout; // Duration after which nominee can take control
address nominee; // Address authorized to recover the account
}

State Variables

  • mapping(address account => DeadmanSwitchStorage) public config: Maps accounts to their DeadmanSwitch configuration

Events

  1. ModuleInitialized(address indexed account, address nominee, uint48 timeout)
  2. ModuleUninitialized(address indexed account)
  3. NomineeSet(address indexed account, address nominee)
  4. TimeoutSet(address indexed account, uint48 timeout)

Errors

  • UnsupportedOperation(): Thrown when attempting unsupported operations
  • AlreadyInitialized(address): Thrown when trying to initialize an already initialized account
  • NotInitialized(address): Thrown when performing operations on an uninitialized account

Core Functionality

Module Management

onInstall

function onInstall(bytes calldata data) external

Initializes the DeadmanSwitch for an account.

  • Data format: abi.encodePacked(nominee, timeout)
  • Nominee: first 20 bytes (address)
  • Timeout: next 6 bytes (uint48)
  • Emits ModuleInitialized event

onUninstall

function onUninstall(bytes calldata) external

Removes the DeadmanSwitch configuration.

  • Clears all stored data
  • Emits ModuleUninitialized event

isInitialized

function isInitialized(address smartAccount) public view returns (bool)

Checks if an account has initialized the module.

  • Returns true if nominee is set (non-zero address)

Configuration Functions

setNominee

function setNominee(address nominee) external

Updates the nominee address.

  • Requires initialized module
  • Emits NomineeSet event

setTimeout

function setTimeout(uint48 timeout) external

Updates the timeout duration.

  • Requires initialized module
  • Emits TimeoutSet event

Hook Functions

_preCheck

function _preCheck(
address account,
address,
uint256,
bytes calldata
) internal override returns (bytes memory hookData)

Updates last access time before execution.

  • Only updates if module is initialized
  • Returns empty string

_postCheck

function _postCheck(address, bytes calldata) internal override

Post-execution hook (currently unused).

Validation Functions

validateUserOp

function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash
) external override returns (ValidationData)

Validates user operations for account recovery.

  • Checks nominee's signature
  • Verifies timeout period
  • Returns packed validation data:
    • Signature validity
    • Valid after timestamp (timeout)
    • Valid until (max uint48)

isValidSignatureWithSender

function isValidSignatureWithSender(
address,
bytes32,
bytes calldata
) external pure override returns (bytes4)

ERC-1271 signature validation (unsupported).

  • Always reverts with UnsupportedOperation

Metadata Functions

isModuleType

function isModuleType(uint256 typeID) external pure returns (bool)

Identifies supported module types.

  • Returns true for TYPE_HOOK or TYPE_VALIDATOR

name

function name() external pure virtual returns (string memory)

Returns module name: "DeadmanSwitch"

version

function version() external pure virtual returns (string memory)

Returns module version: "1.0.0"

Technical Specifications

  1. Timing Mechanism

    • Uses uint48 for timestamps and timeouts
    • Updates lastAccess on every valid operation
    • Recovery window opens after lastAccess + timeout
  2. Security Features

    • Nominee signature required for recovery
    • ERC-1271 signatures explicitly unsupported
    • Module can be uninstalled by the account owner
  3. Gas Optimization

    • Uses uint48 for timestamps to save storage
    • Implements view functions where possible

Integration Guide

To integrate this module:

  1. Deploy the DeadmanSwitch contract
  2. Install the module on the target account with:
    bytes memory initData = abi.encodePacked(nomineeAddress, timeoutInSeconds);
    // Call installation method with initData
  3. Ensure the account's validation flow includes this module

Example Usage

// Installation
bytes memory initData = abi.encodePacked(
address(0x1234...), // nominee
uint48(7 days) // timeout
);
account.installModule(deadmanSwitch, initData);

// Updating nominee
deadmanSwitch.setNominee(newNomineeAddress);

// Updating timeout
deadmanSwitch.setTimeout(uint48(14 days));

Security Considerations

  1. Recovery Window

    • Nominee can only recover after timeout
    • Each account interaction resets the timer
  2. Access Control

    • Only account owner can change nominee and timeout
    • Only nominee can execute recovery
  3. Limitations

    • No emergency override
    • Timeout period is fixed once set

Best Practices

  1. Choose an appropriate timeout period
  2. Select a trusted nominee
  3. Regularly verify nominee and timeout settings
  4. Consider backup recovery mechanisms